package com.meta.utils
{
	import flash.external.ExternalInterface;
	import flash.utils.getTimer;

	public class JSPort
	{
		public static const PUT:String= "PUT";
		public static const POST:String= "POST";
		public static const GET:String= "GET";
		public static const DELETE:String= "DELETE";
		private static var _instance:JSPort;
		public static function get instance():JSPort { return _instance||=new JSPort; }


		public function JSPort()
		{
			trace("JSPort.JSPort()",ExternalInterface.available,ExternalInterface.objectID);
			ExternalInterface.addCallback("callback",backFunc);
			ExternalInterface.addCallback("directback",getobj);
			ExternalInterface.addCallback("successBack",successBack);
			ExternalInterface.addCallback("errorBack",errorBack);
//			defineFunc("haha123","function () { return 123}")
//			callFunc("haha123")
			initExJs();
		}
		private function initExJs():void
		{
			evalJs("function getMovie() {	return document.getElementById('" +ExternalInterface.objectID +"'); }")
//			evalJs("function request(route, className, objectId, method, dataObject,t) {AV._request(route,className,objectId,method,dataObject).then(function (obj){getMovie().successBack(t,obj);},function (error){	getMovie().errorBack(t,error);})};");
//			evalJs("function fetchUser(obj){var user = AV.User._currentUser = AV.Object._create('_User');user._finishFetch(obj);}"); 

		}
		public function callFunc(name:String,...params):void
		{
			var a:Array = [name].concat(params);
			var o:Object = ExternalInterface.call.apply(this,a);
		}
		public function evalCallback(body:String):void
		{
			evalJs("getMovie().directback(" +body+")");
		}
		public function callFunc$func(jsStr:String,...args):void
		{
			var t:String =  (getTimer()+Math.random()).toFixed(2);
			CALLBACK_MAP["callbackFunc"][t]= args;
			var a:Array  = jsStr.split("$func");
			var str:String = "";
			a.forEach(function (item:String,index:int,arr:Array):void{
				str += item;
				if(index != arr.length-1){
					str+=factory(index)
				}
			});
			trace("JSPort.callFunc$func(jsStr, args)",str);
			evalJs(str);
			function factory (i:int):String{
				return "function (){var t="+t+";getMovie().directback(t,"+i+",[].slice.call(arguments))}"
			}


//			callFunc.apply(this,[name].concat(args,t));
		}		
		public function callFuncWithBack(name:String,callback:Function,...args):void
		{
			var t:String =  (getTimer()+Math.random()).toFixed(2);
			CALLBACK_MAP["callback"][t]= callback
			callFunc.apply(this,[name].concat(args,t));
		}
		public function request(route:String, className:String, objectId:String, method:String, dataObject:Object,success:Function,error:Function):void
		{
			callFuncWithSuccAndError("request",success,error,route, className, objectId, method, dataObject);
		}
		public function callFuncWithSuccAndError(name:String,success:Function,error:Function,...args):void
		{
			var t:String =  (getTimer()+Math.random()).toFixed(2);
			CALLBACK_MAP["successBack"][t]= success
			CALLBACK_MAP["errorBack"][t]= error
			callFunc.apply(this,[name].concat(args,t));
		}
		public function evalJs(body:String):void
		{
			callFunc("eval",body);
		}
		public function defineFunc(name:String,functionbody:String):void
		{
			callFunc("eval","var "+name+" =" +functionbody);
		}
		private const CALLBACK_MAP:Object = {
				callback:{},
				callbackFunc:{},
				successBack:{},
				errorBack:{}
			};
		public function getobj(...args):void
		{
			trace("JSPort.getobj(args)",args);
			callbackhandle("callbackFunc",args)
		}
		public function backFunc(...args):void
		{
			trace("JSPort.backFunc(args)",args);
//			CALLBACK_MAP["callback"][args.shift()](args);
			callbackhandle("callback",args)
		}
		public function successBack(...args):void
		{
			trace("JSPort.successBack(args)",args);
//			CALLBACK_MAP["successBack"][args.shift()](args);
			callbackhandle("successBack",args)
		}
		public function errorBack(...args):void
		{
			trace("JSPort.errorBack(args)",args);
//			CALLBACK_MAP["errorBack"][args.shift()](args);
			callbackhandle("errorBack",args)
		}
		private function callbackhandle(name:String,args:Array):void
		{
			var obj:Object = CALLBACK_MAP[name];
			if(args && args.length)
			{
				var t:String= args.shift()
				var call:Object= obj[t];
				if(call)
				{
					if(call is Function){
						trace("JSPort.callbackhandle",JSON.stringify(args));
						call.apply(this,args);
					}
					else{
						for  (var i in call) 
						{
							call[i].apply(null,args[args.length-1]);
						}
					}
					delete obj[t];

				}
			}
		}
	}
}

